package com.nodecollege.cloud.service.impl;

import com.nodecollege.cloud.common.UpmsConstants;
import com.nodecollege.cloud.common.exception.UpmsException;
import com.nodecollege.cloud.common.model.LoginUser;
import com.nodecollege.cloud.common.model.QueryVO;
import com.nodecollege.cloud.common.model.UpmsToken;
import com.nodecollege.cloud.common.model.po.UpmsUser;
import com.nodecollege.cloud.common.model.vo.LoginVO;
import com.nodecollege.cloud.common.utils.NCUtils;
import com.nodecollege.cloud.common.utils.RedisUtils;
import com.nodecollege.cloud.core.utils.PasswordUtil;
import com.nodecollege.cloud.dao.mapper.UpmsUserMapper;
import com.nodecollege.cloud.service.LoginService;
import com.nodecollege.cloud.service.MemberService;
import com.nodecollege.cloud.service.PasswordPolicyService;
import com.nodecollege.cloud.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.List;

/**
 * @author LC
 * @date 2019/6/21 18:22
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    private static Long expire = 2 * 60 * 60L;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UpmsUserMapper upmsUserMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private PasswordPolicyService passwordPolicyService;

    @Autowired
    private MemberService memberService;

    /**
     * 用户注册
     *
     * @param loginVO
     */
    @Override
    public void register(LoginVO loginVO) {
        userService.addUser(loginVO);
    }

    /**
     * 用户登录
     *
     * @param loginVO
     */
    @Override
    public UpmsToken login(LoginVO loginVO) {
        // 1 登陆前验证密码策略
        passwordPolicyService.checkUserLoginPolicy(loginVO.getAccount(), loginVO.getPassword(),
                loginVO.getPassword(), loginVO.getImageCert());

        // 2 验证密码是否正确
        UpmsUser user = new UpmsUser();
        user.setAccount(loginVO.getAccount());
        List<UpmsUser> result = upmsUserMapper.selectUserListByMap(new QueryVO<>(user).toMap());
        if (result.isEmpty()) {
            user.setAccount(null);
            user.setTelephone(loginVO.getTelephone());
            result = upmsUserMapper.selectUserListByMap(new QueryVO<>(user).toMap());
            NCUtils.nullOrEmptyThrow(result, new UpmsException("-1", "根据账号或者电话未获取到用户信息"));
        }
        user = result.get(0);
        if (!user.getPassword().equals(PasswordUtil.md5(loginVO.getPassword(), user.getSalt()))) {
            Integer loginFileNum = passwordPolicyService.setUserLoginFileNum(loginVO.getAccount());
            throw new UpmsException("-1", MessageFormat.format("密码错误！请重新输入！(第{0}次)", loginFileNum));
        }

        // 3 登陆成功后校验密码策略
        Boolean checkPasswordValidity = passwordPolicyService.checkUserLoginSuccessPolicy(user.getUserId(), user.getFirstLogin());
        if (!checkPasswordValidity) {
            if (StringUtils.isBlank(loginVO.getNewPassword()) || StringUtils.isBlank(loginVO.getImageCert())) {
                throw new UpmsException("10001", "首次登陆，或者密码已过密码有效期，请重新设置新密码！");
            }
        }

        // 4 生成token
        // 访问令牌
        String accessToken = NCUtils.getUUID();
        // 成员信息令牌 当成员信息令牌改变时，说明成员信息有更新，需重新获取用户信息
        String infoRandom = NCUtils.getUUID();
        user = userService.getUserByUserId(user.getUserId());
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getUserId());
        loginUser.setAccount(user.getAccount());
        loginUser.setName(StringUtils.isBlank(user.getNickname()) ? user.getAccount() : user.getNickname());
        loginUser.setAvatar(user.getAvatar());
        loginUser.setAccessToken(accessToken);
        loginUser.setInfoRandom(infoRandom);
        loginUser.setExpire(expire);
        loginUser.setTenantId(user.getTenantId());
        loginUser.setAvatar(user.getAvatar());
        loginUser.setAvatarThumb(user.getAvatarThumb());

        // 初始化用户信息数据权限信息
        memberService.initMemberDataPower(loginUser);
        redisUtils.set(UpmsConstants.USER_LOGIN_INFO + accessToken, loginUser, expire);

        // 清除登录失败次数缓存
        passwordPolicyService.deleteUserLoginFileNum(loginVO.getAccount());

        UpmsToken upmsToken = new UpmsToken();
        upmsToken.setAccessToken(accessToken);
        upmsToken.setInfoRandom(infoRandom);
        upmsToken.setExpire(expire);
        return upmsToken;
    }

    /**
     * 注销登录
     *
     * @param token
     */
    @Override
    public void logout(String token) {
        redisUtils.delete(UpmsConstants.USER_LOGIN_INFO + token);
    }

    /**
     * 根据token获取用户信息
     *
     * @param token
     * @return
     */
    @Override
    public LoginUser getUserInfo(String token) {
        return redisUtils.get(UpmsConstants.USER_LOGIN_INFO + token, LoginUser.class);
    }

    /**
     * 未登陆情况下修改密码
     *
     * @param loginVO
     */
    @Override
    public void updatePwdNoLogin(LoginVO loginVO) {

        NCUtils.nullOrEmptyThrow(loginVO.getAccount(), new UpmsException("-1", "账号必填！"));
        NCUtils.nullOrEmptyThrow(loginVO.getPassword(), new UpmsException("-1", "旧密码必填！"));
        NCUtils.nullOrEmptyThrow(loginVO.getNewPassword(), new UpmsException("-1", "新密码必填！"));

        // 1 登陆前验证密码策略
        passwordPolicyService.checkLoginPolicy(loginVO.getAccount(), loginVO.getPassword(),
                loginVO.getPassword(), loginVO.getImageCert());

        // 2 验证密码是否正确
        UpmsUser user = userService.getUserByAccount(loginVO.getAccount());

        if (!user.getPassword().equals(PasswordUtil.md5(loginVO.getPassword(), user.getSalt()))) {
            Integer loginFileNum = passwordPolicyService.setLoginFileNum(loginVO.getAccount());
            throw new UpmsException("-1", MessageFormat.format("密码错误！请重新输入！(第{0}次)", loginFileNum));
        }

        // 更新密码
        userService.updatePwd(user.getUserId(), loginVO.getPassword(), loginVO.getNewPassword(), null);
    }
}
